package jmetal.metaheuristics.singleObjective;

import java.util.HashMap;

import jmetal.core.Algorithm;
import jmetal.core.Operator;
import jmetal.core.Problem;
import jmetal.core.SolutionSet;
import jmetal.metaheuristics.singleObjective.geneticAlgorithm.gGA;
import jmetal.metaheuristics.singleObjective.island.IslandFTGAController;
import jmetal.metaheuristics.singleObjective.island.IslandLTGAController;
import jmetal.metaheuristics.singleObjective.panmitic.PanmiticFTGA;
import jmetal.metaheuristics.singleObjective.panmitic.PanmiticLTGA;
import jmetal.operators.crossover.CrossoverFactory;
import jmetal.operators.mutation.MutationFactory;
import jmetal.operators.selection.SelectionFactory;
import jmetal.problems.singleObjective.Griewank;
import jmetal.util.JMException;

public class TccConsolMain {
	public static void main(String[] args) throws Exception {
		// Problem problem = new Sphere("Real", 10);
		Problem problem = new Griewank("Real", 5);
		Operator crossover; // Crossover operator
		Operator mutation; // Mutation operator
		Operator selection; // Selection operator
		int execs = 50;
		HashMap parameters; // Operator parameters

		parameters = new HashMap();
		parameters.put("probability", 0.9);
		parameters.put("distributionIndex", 20.0);
		crossover = CrossoverFactory.getCrossoverOperator("SBXCrossover", parameters);

		parameters = new HashMap();
		parameters.put("probability", 1.0 / problem.getNumberOfVariables());
		parameters.put("distributionIndex", 20.0);
		mutation = MutationFactory.getMutationOperator("PolynomialMutation", parameters);

		parameters = null;
		selection = SelectionFactory.getSelectionOperator("BinaryTournament", parameters);

		double[][] timeResults = new double[execs][5];
		double[][] valueResults = new double[execs][5];
		double[] ret = null;
		for (int i = 0; i < execs; i++) {
			ret = runSequentialGa(problem, crossover, mutation, selection);
			timeResults[i][0] = ret[0];
			valueResults[i][0] = ret[1];

			ret = runPanmiticLogical(problem, crossover, mutation, selection);
			timeResults[i][1] = ret[0];
			valueResults[i][1] = ret[1];

			ret = runPanmiticPhysical(problem, crossover, mutation, selection);
			timeResults[i][2] = ret[0];
			valueResults[i][2] = ret[1];

			ret = runIslandLogical(problem, crossover, mutation, selection);
			timeResults[i][3] = ret[0];
			valueResults[i][3] = ret[1];

			ret = runIslandPhysical(problem, crossover, mutation, selection);
			timeResults[i][4] = ret[0];
			valueResults[i][4] = ret[1];
		}

		for (int i = 0; i < execs; i++) {
			System.out.printf("%e\t%e\t%e\t%e\t%e\t%e\t%e\t%e\t%e\t%e\t\n", timeResults[i][0], timeResults[i][1],
					timeResults[i][2], timeResults[i][3], timeResults[i][4], valueResults[i][0], valueResults[i][1],
					valueResults[i][2], valueResults[i][3], valueResults[i][4]);
		}

	}

	private static double[] runSequentialGa(Problem problem, Operator crossover, Operator mutation, Operator selection)
			throws JMException, ClassNotFoundException {
		double[] ret = new double[2];
		Algorithm algorithm; // The algorithm to use
		algorithm = new gGA(problem); // Generational GA

		execute(crossover, mutation, selection, ret, algorithm);
		System.out.printf("SEQ %.5f\t%e\t%d\n ", ret[0], ret[1], gGA.evaluationsTotal);
		return ret;
	}

	private static double[] runPanmiticLogical(Problem problem, Operator crossover, Operator mutation,
			Operator selection) throws JMException, ClassNotFoundException {
		double[] ret = new double[2];
		Algorithm algorithm = new PanmiticLTGA(problem);

		execute(crossover, mutation, selection, ret, algorithm);
		System.out.printf("PL %.5f\t%e\t%d\n ", ret[0], ret[1], PanmiticLTGA.evaluationsTotal);
		return ret;
	}

	private static double[] runPanmiticPhysical(Problem problem, Operator crossover, Operator mutation,
			Operator selection) throws JMException, ClassNotFoundException {
		double[] ret = new double[2];
		Algorithm algorithm = new PanmiticFTGA(problem);

		execute(crossover, mutation, selection, ret, algorithm);
		System.out.printf("PF %.5f\t%e\t%d\n ", ret[0], ret[1], PanmiticFTGA.evaluationsTotal);
		return ret;
	}

	private static double[] runIslandLogical(Problem problem, Operator crossover, Operator mutation, Operator selection)
			throws JMException, ClassNotFoundException {
		double[] ret = new double[2];
		Algorithm algorithm = new IslandLTGAController(problem);

		execute(crossover, mutation, selection, ret, algorithm);
		System.out.printf("IL %.5f\t%e\t%d\n ", ret[0], ret[1], IslandLTGAController.evaluationsTotal);

		return ret;
	}

	private static double[] runIslandPhysical(Problem problem, Operator crossover, Operator mutation, Operator selection)
			throws JMException, ClassNotFoundException {
		double[] ret = new double[2];
		Algorithm algorithm = new IslandFTGAController(problem);

		execute(crossover, mutation, selection, ret, algorithm);
		System.out.printf("IP %.5f\t%e\t%d\n ", ret[0], ret[1], IslandFTGAController.evaluationsTotal);
		return ret;
	}

	private static void execute(Operator crossover, Operator mutation, Operator selection, double[] ret,
			Algorithm algorithm) throws JMException, ClassNotFoundException {
		algorithm.setInputParameter("populationSize", 100);
		algorithm.setInputParameter("maxEvaluations", 1000000);

		algorithm.addOperator("crossover", crossover);
		algorithm.addOperator("mutation", mutation);
		algorithm.addOperator("selection", selection);

		double initTime = System.currentTimeMillis();
		SolutionSet population = algorithm.execute();

		double estimatedTime = System.currentTimeMillis() - initTime;

		population.printObjectivesToFile("FUN");
		population.printVariablesToFile("VAR");

		ret[0] = estimatedTime / 1000;
		ret[1] = population.get(0).getObjective(0);
	}

}
